/**
 * animOnScroll.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2013, Codrops
 * http://www.codrops.com
 */
;( function( window ) {
 
 'use strict';
 
 var docElem = window.document.documentElement;

 function getViewportH() {
  var client = docElem['clientHeight'],
   inner = window['innerHeight'];
  
  if( client < inner )
   return inner;
  else
   return client;
 }

 function scrollY() {
  return window.pageYOffset || docElem.scrollTop;
 }

 // http://stackoverflow.com/a/5598797/989439
 function getOffset( el ) {
  var offsetTop = 0, offsetLeft = 0;
  do {
   if ( !isNaN( el.offsetTop ) ) {
    offsetTop += el.offsetTop;
   }
   if ( !isNaN( el.offsetLeft ) ) {
    offsetLeft += el.offsetLeft;
   }
  } while( el = el.offsetParent )

  return {
   top : offsetTop,
   left : offsetLeft
  }
 }

 function inViewport( el, h ) {
  var elH = el.offsetHeight,
   scrolled = scrollY(),
   viewed = scrolled + getViewportH(),
   elTop = getOffset(el).top,
   elBottom = elTop + elH,
   // if 0, the element is considered in the viewport as soon as it enters.
   // if 1, the element is considered in the viewport only when it's fully inside
   // value in percentage (1 >= h >= 0)
   h = h || 0;

  return (elTop + elH * h) <= viewed && (elBottom - elH * h) >= scrolled;
 }

 function extend( a, b ) {
  for( var key in b ) { 
   if( b.hasOwnProperty( key ) ) {
    a[key] = b[key];
   }
  }
  return a;
 }

 function AnimOnScroll( el, options ) { 
  this.el = el;
  this.options = extend( this.defaults, options );
  this._init();
 }

 AnimOnScroll.prototype = {
  defaults : {
   // Minimum and a maximum duration of the animation (random value is chosen)
   minDuration : 0,
   maxDuration : 0,
   // The viewportFactor defines how much of the appearing item has to be visible in order to trigger the animation
   // if we'd use a value of 0, this would mean that it would add the animation class as soon as the item is in the viewport. 
   // If we were to use the value of 1, the animation would only be triggered when we see all of the item in the viewport (100% of it)
   viewportFactor : 0
  },
  _init : function() {
   this.items = Array.prototype.slice.call( document.querySelectorAll( '#' + this.el.id + ' > li' ) );
   this.itemsCount = this.items.length;
   this.itemsRenderedCount = 0;
   this.didScroll = false;

   var self = this;

   imagesLoaded( this.el, function() {
    
    // initialize masonry
    new Masonry( self.el, {
     itemSelector: 'li',
     transitionDuration : 0
    } );
    
    if( Modernizr.cssanimations ) {
     // the items already shown...
     self.items.forEach( function( el, i ) {
      if( inViewport( el ) ) {
       self._checkTotalRendered();
       classie.add( el, 'shown' );
      }
     } );

     // animate on scroll the items inside the viewport
     window.addEventListener( 'scroll', function() {
      self._onScrollFn();
     }, false );
     window.addEventListener( 'resize', function() {
      self._resizeHandler();
     }, false );
    }

   });
  },
  _onScrollFn : function() {
   var self = this;
   if( !this.didScroll ) {
    this.didScroll = true;
    setTimeout( function() { self._scrollPage(); }, 60 );
   }
  },
  _scrollPage : function() {
   var self = this;
   this.items.forEach( function( el, i ) {
    if( !classie.has( el, 'shown' ) && !classie.has( el, 'animate' ) && inViewport( el, self.options.viewportFactor ) ) {
     setTimeout( function() {
      var perspY = scrollY() + getViewportH() / 2;
      self.el.style.WebkitPerspectiveOrigin = '50% ' + perspY + 'px';
      self.el.style.MozPerspectiveOrigin = '50% ' + perspY + 'px';
      self.el.style.perspectiveOrigin = '50% ' + perspY + 'px';

      self._checkTotalRendered();

      if( self.options.minDuration && self.options.maxDuration ) {
       var randDuration = ( Math.random() * ( self.options.maxDuration - self.options.minDuration ) + self.options.minDuration ) + 's';
       el.style.WebkitAnimationDuration = randDuration;
       el.style.MozAnimationDuration = randDuration;
       el.style.animationDuration = randDuration;
      }
      
      classie.add( el, 'animate' );
     }, 25 );
    }
   });
   this.didScroll = false;
  },
  _resizeHandler : function() {
   var self = this;
   function delayed() {
    self._scrollPage();
    self.resizeTimeout = null;
   }
   if ( this.resizeTimeout ) {
    clearTimeout( this.resizeTimeout );
   }
   this.resizeTimeout = setTimeout( delayed, 1000 );
  },
  _checkTotalRendered : function() {
   ++this.itemsRenderedCount;
   if( this.itemsRenderedCount === this.itemsCount ) {
    window.removeEventListener( 'scroll', this._onScrollFn );
   }
  }
 }

 // add to global namespace
 window.AnimOnScroll = AnimOnScroll;

} )( window );